package org.jsola.hr.service.impl;

import cn.hutool.core.io.FileUtil;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.jsola.common.DateKit8;
import org.jsola.contract.constant.AccountType;
import org.jsola.contract.constant.SealType;
import org.jsola.contract.constant.SignMethod;
import org.jsola.contract.dto.ContractUpdateDTO;
import org.jsola.contract.dto.SignWeiXinSendDTO;
import org.jsola.contract.entity.AccountDO;
import org.jsola.contract.entity.AppendixDO;
import org.jsola.contract.entity.ContractDO;
import org.jsola.contract.entity.SealPositionDO;
import org.jsola.contract.service.IContractSignCallbackService;
import org.jsola.contract.vo.CategoryVO;
import org.jsola.contract.vo.PartySignAccountVO;
import org.jsola.contract.vo.SealVO;
import org.jsola.core.entity.BaseDO;
import org.jsola.file.entity.FileVersionDO;
import org.jsola.file.service.ISiteFileService;
import org.jsola.hr.common.JunZiQianUtil;
import org.jsola.hr.common.NoticeKit;
import org.jsola.hr.constant.*;
import org.jsola.hr.core.JunZiQianProperties;
import org.jsola.hr.dto.CheckInPeopleUpdateDTO;
import org.jsola.hr.entity.CheckInPeopleDO;
import org.jsola.hr.entity.EmpChangesDO;
import org.jsola.hr.entity.EmpInfoDO;
import org.jsola.hr.entity.PersonalEventDO;
import org.jsola.hr.provider.*;
import org.jsola.hr.service.*;
import org.jsola.hr.vo.CompanyVO;
import org.jsola.hr.vo.junziqian.*;
import org.jsola.json.JsonKit;
import org.jsola.message.dto.WeiXinDTO;
import org.jsola.message.dto.WxTemplateParam;
import org.jsola.notice.constant.NoticeConstants;
import org.jsola.notice.vo.NoticeRuleSettingVO;
import org.jsola.user.core.TokenUser;
import org.jsola.user.entity.UnionOpenIdDO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.io.File;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author ds
 */
@Service("contractSignCallbackServiceImpl")
@Slf4j
public class ContractSignCallbackServiceImpl implements IContractSignCallbackService {

    @Autowired
    private IPersonalEventService personalEventService;

    @Autowired
    private IEmpInfoService empInfoService;

    @Autowired
    private IEmpChangesService empChangesService;

    @Autowired
    private IContractProviderService contractProviderService;

    @Autowired
    private ICheckInPeopleService checkInPeopleService;

    @Autowired
    private IUserProviderService userProviderService;

    @Autowired
    private ISiteConfigProviderService siteConfigProviderService;

    @Autowired
    private IMessageProviderService messageProviderService;

    @Autowired
    private INoticeProviderService noticeProviderService;

    @Autowired
    private ICompanyService companyService;

    @Autowired
    private JunZiQianProperties junZiQianProperties;

    @Autowired
    private ISiteFileService siteFileService;

    @Override
    public void onPublish(ContractDO contractDO, List<PartySignAccountVO> list, AppendixDO appendixDO, TokenUser tokenUser) {
        log.info("合同成功发起回调");
        //  Step1: 发起签约
        ContractPublishVO publishVO = new ContractPublishVO();
        publishVO.setContractName(contractDO.getName());

        // 单边签署设置归档
        CategoryVO category = contractProviderService.selectCategoryById(contractDO.getCategoryId(), tokenUser.getSiteId());
        List<SealPositionDO> positions = contractProviderService.selectByContractId(contractDO.getId(), tokenUser);
        Map<Integer, List<SealPositionDO>> map = positions.stream().collect(Collectors.groupingBy(SealPositionDO::getAccountType));
        List<SignatoryVO> vos = list.stream().sorted(Comparator.comparing(PartySignAccountVO::getType))
                .map(s -> {
                    // 双边签署或者员工单边签署的时候传参
                    if ((SignMethod.BOTH.getValue().equals(category.getSignType())
                            || SignMethod.PERSON_ONLY.getValue().equals(category.getSignType())) && s.getType() == 1) {
                        SignatoryVO sign = new SignatoryVO();
                        sign.setServerCaAuto(0);
                        sign.setSignLevel(1);
                        // 1个人 2企业
                        EmpInfoDO empInfoDO = empInfoService.selectByUserId(s.getMemberId(), contractDO.getSubjectId(), tokenUser.getSiteId());
                        sign.setFullName(empInfoDO.getName());
                        sign.setIdentityType(1);
                        sign.setOrderNum(1);
                        sign.setMobile(contractDO.getPartyBPhone());
                        // 查询身份证/统一社会信用代码号
                        sign.setIdentityCard(empInfoDO.getIdCard());
                        if (Boolean.TRUE.equals(contractDO.getIsCheckFace())) {
                            sign.setAuthLevel(new String[]{"11"});
                        } else {
                            sign.setAuthLevel(new String[]{"12"});
                        }
                        List<SealPositionDO> dos = map.get(AccountType.PERSON.getValue());
                        if (!CollectionUtils.isEmpty(dos)) {
                            Map<Integer, List<SealPositionDO>> pageMap = dos.stream().collect(Collectors.groupingBy(SealPositionDO::getSealPage));
                            List<PositionVO> positionList = new ArrayList<>();
                            pageMap.forEach((page, pagePositions) -> {
                                PositionVO positionVO = new PositionVO();
                                positionVO.setPage(page - 1);
                                List<PositionVO.Chapte> chaptes = pagePositions.stream().map(position -> {
                                    PositionVO.Chapte chapte = new PositionVO.Chapte();
                                    //  处理坐标
                                    chapte.setOffsetX(Double.parseDouble(position.getSealPositionX()));
                                    chapte.setOffsetY(Double.parseDouble(position.getSealPositionY()));
                                    return chapte;
                                }).collect(Collectors.toList());
                                positionVO.setChaptes(chaptes);
                                positionList.add(positionVO);
                            });
                            sign.setChapteJson(JsonKit.toJSONString(positionList));
                        }
                        return sign;
                    }
                    // 企业单边签署的时候才传，双边签署用追加的方式
                    else if (SignMethod.ENTERPRISE_ONLY.getValue().equals(category.getSignType()) && s.getType() == 2) {
                        SignatoryVO sign = new SignatoryVO();
                        AccountDO accountDO = contractProviderService.findAccount(AccountType.ENTERPRISE, s.getMemberId());
                        sign.setServerCaAuto(1);
                        sign.setFullName(accountDO.getName());
                        sign.setIdentityType(12);
                        sign.setOrderNum(2);
                        sign.setEmail(accountDO.getAccountId());
                        sign.setIdentityCard(accountDO.getOrganCode());
                        if (category.getEnterpriseSealId() != null) {
                            SealVO sealVO = contractProviderService.selectSealById(category.getEnterpriseSealId(), tokenUser.getSiteId());
                            sign.setSignId(Long.valueOf(sealVO.getThirdSealId()));
                        }
                        List<SealPositionDO> dos = map.get(AccountType.ENTERPRISE.getValue());
                        if (!CollectionUtils.isEmpty(dos)) {
                            Map<Integer, List<SealPositionDO>> pageMap = dos.stream().collect(Collectors.groupingBy(SealPositionDO::getSealPage));
                            List<PositionVO> positionList = new ArrayList<>();
                            pageMap.forEach((page, pagePositions) -> {
                                PositionVO positionVO = new PositionVO();
                                positionVO.setPage(page - 1);
                                List<PositionVO.Chapte> chaptes = pagePositions.stream().map(position -> {
                                    PositionVO.Chapte chapte = new PositionVO.Chapte();
                                    //  处理坐标
                                    chapte.setOffsetX(Double.parseDouble(position.getSealPositionX()));
                                    chapte.setOffsetY(Double.parseDouble(position.getSealPositionY()));
                                    return chapte;
                                }).collect(Collectors.toList());
                                positionVO.setChaptes(chaptes);
                                positionList.add(positionVO);
                            });
                            sign.setChapteJson(JsonKit.toJSONString(positionList));
                        }
                        return sign;
                    }
                    return null;
                }).filter(Objects::nonNull).collect(Collectors.toList());
        publishVO.setSignatories(JSON.toJSONString(vos));
        publishVO.setServerCa(1);
        publishVO.setDealType(5);
        publishVO.setFileSuffix(0);
        publishVO.setFileType(0);
        FileVersionDO fileVersionDO = siteFileService.download(appendixDO.getPath(), tokenUser);
        File pdf = new File(fileVersionDO.getTempFilePath());
        File file = new File(pdf.getParentFile(), fileVersionDO.getName());
        if (!file.exists()) {
            FileUtil.copyFile(pdf, file);
        }
        publishVO.setFile(file);
        publishVO.setNoEbqSign(0);
        publishVO.setOrderFlag(1);
        publishVO.setNeedQifengSign(1);
        publishVO.setNotifyUrl(junZiQianProperties.getNotifyUrl());
        // 如果不追加签署方，直接归档
        if (SignMethod.BOTH.getValue().equals(category.getSignType())) {
            publishVO.setIsArchive(0);
        } else {
            publishVO.setIsArchive(1);
        }

        String url = junZiQianProperties.getServicesUrl() + JunZiQianConstants.URL_CONTRACT_PUBLISH;
        JunZiQianResult result = JunZiQianUtil.send(publishVO, junZiQianProperties, url);
        file.delete();

        //  Step2: 君子签合同编号，写回合同表
        String applyNo = String.valueOf(result.getData());
        ContractUpdateDTO contractUpdateDTO = new ContractUpdateDTO();
        contractUpdateDTO.setId(contractDO.getId());
        contractUpdateDTO.setContractNo(applyNo);
        contractProviderService.updateContract(contractUpdateDTO, tokenUser);
        log.info("君子签合同编号，写回合同表===>{}", JSON.toJSONString(contractUpdateDTO));


        if (!SignMethod.ENTERPRISE_ONLY.getValue().equals(category.getSignType())) {
            //  Step3: 个人发短信
            SignatoryVO person = vos.stream().filter(s -> s.getIdentityType() == 1).findAny().orElseGet(SignatoryVO::new);
            String customizeName = "";
            if (!SignMethod.PERSON_ONLY.getValue().equals(category.getSignType())) {
                PartySignAccountVO companySign = list.stream().filter(s -> Objects.equals(s.getType(), 2)).findAny().get();
                AccountDO accountDO = contractProviderService.findAccount(AccountType.ENTERPRISE, companySign.getMemberId());
                customizeName = accountDO.getName();
            }
            SmsVO sms = new SmsVO();
            sms.setApplyNo(applyNo);
            sms.setFullName(person.getFullName());
            sms.setIdentityCard(person.getIdentityCard());
            sms.setIdentityType(1);
            sms.setSignNotifyType(1);
            sms.setCustomizeName(customizeName);
            String urlNotify = junZiQianProperties.getServicesUrl() + JunZiQianConstants.URL_CONTRACT_NOTIFY;
            JunZiQianUtil.send(sms, junZiQianProperties, urlNotify);
        }
    }


    @Override
    public void onSuccess(ContractDO contractDO, List<PartySignAccountVO> list, AppendixDO appendixDO, TokenUser tokenUser) {

        StringBuilder desc = new StringBuilder();
        if (contractDO.getContractNo() != null) {
            desc.append("合同编号为:").append(contractDO.getContractNo());
            desc.append(",");
        }
        if (StringUtils.isNotEmpty(contractDO.getSealType())) {
            desc.append("合同类型为:").append(SealType.find(contractDO.getSealType()).getDesc());
            desc.append(",");
        }
        desc.append("签约时间为：")
                .append(DateFormatUtils.format(contractDO.getSignDate() != null ? contractDO.getSignDate() : new Date(), "yyyy-MM-dd"));
        PersonalEventDO personalEventDO = new PersonalEventDO();
        personalEventDO.setIfAuto(true);
        personalEventDO.setEventTime(new Date());
        personalEventDO.setEventType(PersonalEventEnum.CONTRACT_EMP.getValue());
        personalEventDO.setDescription(desc.toString());
        personalEventDO.setEventName(PersonalEventEnum.CONTRACT_EMP.getDesc());
        personalEventDO.setAttachUrl(appendixDO.getPath());
        if (list.size() > 0) {
            for (PartySignAccountVO partySignAccountVO : list) {
                EmpInfoDO infoDO = empInfoService.selectOnJobByUserIdAndSiteId(partySignAccountVO.getMemberId(), tokenUser);
                if (infoDO != null) {
                    personalEventDO.setUserId(infoDO.getUserId());
                    personalEventDO.setCompanyId(infoDO.getCompanyId());
                    personalEventDO.setEmpId(infoDO.getId());
                    CategoryVO categoryVO =
                            contractProviderService.selectCategoryById(contractDO.getCategoryId(), tokenUser.getSiteId());
                    if (SignMethod.PERSON_ONLY.getValue().equals(categoryVO.getSignType())) {
                        //如果仅员工签署,把这个员工的合同签署状态变成签署完成
                        infoDO.setContractsStatus(3);
                    } else {
                        //把这个员工的合同签署状态变成待公司签署
                        infoDO.setContractsStatus(2);
                    }
                    // 发送通知
                    // sendWeChat(infoDO, contractDO, tokenUser);
                    empInfoService.updateByIdSelective(infoDO, tokenUser.getSiteId(), tokenUser.getUserId());
                    personalEventService.save(personalEventDO, tokenUser.getSiteId(), tokenUser.getUserId());
                }
            }
        }

    }

    @Override
    public void onComplete(ContractDO contractDO, List<PartySignAccountVO> list, AppendixDO appendixDO, TokenUser tokenUser) {
        StringBuilder desc = new StringBuilder();
        if (contractDO.getContractNo() != null) {
            desc.append("合同编号为:").append(contractDO.getContractNo());
            desc.append(",");
        }
        if (StringUtils.isNotEmpty(contractDO.getSealType())) {
            desc.append("合同类型为:").append(SealType.find(contractDO.getSealType()).getDesc());
            desc.append(",");
        }
        desc.append("签约时间为：")
                .append(DateFormatUtils.format(contractDO.getSignDate() != null ? contractDO.getSignDate() : new Date(), "yyyy-MM-dd"));
        // 签署完成 在员工记录中添加企业已签署
        if (list.size() > 0) {
            PersonalEventDO personalEventDO = new PersonalEventDO();
            personalEventDO.setIfAuto(true);
            personalEventDO.setEventTime(new Date());
            personalEventDO.setEventType(PersonalEventEnum.CONTRACT_COMPANY.getValue());
            personalEventDO.setDescription(desc.toString());
            personalEventDO.setEventName(PersonalEventEnum.CONTRACT_COMPANY.getDesc());
            personalEventDO.setAttachUrl(appendixDO.getPath());
            for (PartySignAccountVO partySignAccountVO : list) {
                EmpInfoDO infoDO = empInfoService.selectOnJobByUserIdAndSiteId(partySignAccountVO.getMemberId(), tokenUser);
                if (infoDO != null) {
                    personalEventDO.setUserId(infoDO.getUserId());
                    personalEventDO.setCompanyId(infoDO.getCompanyId());
                    personalEventDO.setEmpId(infoDO.getId());
                    personalEventService.save(personalEventDO, tokenUser.getSiteId(), tokenUser.getUserId());
                }
            }
        }
        //签署完成,需要把员工的合同签署状态改为签署完成
        EmpInfoDO empInfoDO = contractProviderService.selectEmpInfoByContractId(contractDO.getId());
        if (empInfoDO == null) {
            log.error("根据手机号没有找到员工：{}", contractDO.getPartyBPhone());
            return;
        }
        empInfoDO.setContractsStatus(3);
        if (empInfoDO.getStatus() == 3) {
            // 如果该人员是预登记人员  则预登记人员状态改为已离职
            String phone = empInfoDO.getPhone();
            CheckInPeopleDO checkInPeopleDO = checkInPeopleService.selectByPhone(phone, tokenUser.getSiteId());
            if (Objects.nonNull(checkInPeopleDO)) {
                // 修改该人员的状态
                CheckInPeopleUpdateDTO checkInPeopleUpdateDTO = new CheckInPeopleUpdateDTO();
                checkInPeopleUpdateDTO.setId(checkInPeopleDO.getId());
                checkInPeopleUpdateDTO.setWorkStatus(CheckInPeopleConstant.WORK_STATUS_DIMISSION);
                checkInPeopleUpdateDTO.setStatus(CheckInPeopleConstant.STATUS_DIMISSION);
                checkInPeopleService.update(checkInPeopleUpdateDTO, tokenUser);
            }
            // 离职合同
            String lastChangesId = empChangesService.getLastChangesId(empInfoDO.getId(), EmpChangeType.LEAVE.getValue(), tokenUser.getSiteId());
            if (!StringUtils.isEmpty(lastChangesId)) {
                EmpChangesDO empChangesDO = empChangesService.selectDOById(lastChangesId, tokenUser.getSiteId());
                empInfoDO.setChangeStatus(0);
                empInfoDO.setLeaveDate(empChangesDO.getPreQuitDate());
                empInfoDO.setStatus(EmpInfoStatus.HAS_QUIT.getValue());
                empChangesService.updateEmpChangeStatus(lastChangesId, tokenUser);
            }
        }
        empInfoService.updateByIdSelective(empInfoDO, tokenUser.getSiteId(), tokenUser.getUserId());
    }

    @Override
    public void onExpired(List<ContractDO> contractList) {
        // 查询花名册电子合同
        List<EmpInfoDO> empInfoDOList = contractProviderService
                .selectEmpInfoByContractIds(contractList.parallelStream().map(BaseDO::getId).collect(Collectors.toList()));
        for (EmpInfoDO empInfoDO : empInfoDOList) {
            empInfoDO.setContractsStatus(-1);
            empInfoService.updateByIdSelective(empInfoDO, empInfoDO.getSiteId(), "onExpired");
        }
    }


    @Override
    public void onFailed(ContractDO contractDO, String s, TokenUser tokenUser) {

    }

    @Override
    public void sendMessage(List<SignWeiXinSendDTO> sendList, String subjectName, TokenUser tokenUser) {
        log.info("TODO 合同发送短信回调");
       /* try {
            if (StringUtils.isEmpty(subjectName)) {
                sendNoticeService.sendWaitViewWeiXinTemp(sendList, tokenUser);
            } else {
                sendNoticeService.sendWaitSignWeiXinTemp(sendList, subjectName, tokenUser);
            }
        } catch (Exception e){
            log.error("合同发送短信回调失败", e);
        }*/

    }

    /**
     * 异步发送合同签署完成-微信公众号模板消息
     *
     * @param contractDO 合同信息
     * @param tokenUser  当前用户
     */
    @Async
    void sendWeChat(EmpInfoDO empInfoDO, ContractDO contractDO, TokenUser tokenUser) {
        try {
            if (!ContractsStatus.WAIT_FOR_COMPANY.getValue().equals(contractDO.getStatus())) {
                log.info("合同状态：{}，不发送微信提醒", contractDO.getStatus());
                return;
            }
            String appId = siteConfigProviderService.selectValueByCode(ConfigCodeConstants.CODE_APPID_ADMIN, tokenUser.getSiteId());
            String templateId = siteConfigProviderService.selectValueByCode(ConfigCodeConstants.CODE_CONTRACT_EMP_SIGN_OVER_ADMIN, tokenUser.getSiteId());
            String companyId = contractDO.getSubjectId();
            String companyName = "";
            CompanyVO companyVO = companyService.selectBaseCompanyById(companyId, tokenUser.getSiteId());
            if (companyVO != null) {
                companyName = companyVO.getName();
            } else {
                log.error("查询用工单位错误，companyId：{}, tokenUser：{}", companyId, tokenUser);
            }
            String noticeCode = NoticeConstants.CONTRACT_EMP_SIGN_OVER;
            NoticeRuleSettingVO ruleSettingVO = noticeProviderService.selectByTypeCodeAndCompany(HrConstants.HR_SUBJECT_TYPE,
                    noticeCode, companyId);
            if (ruleSettingVO == null) {
                log.info(noticeCode + "通知设置为空，不发送微信提醒");
                return;
            }
            if (!ruleSettingVO.getEnableStatus()) {
                log.info(noticeCode + "通知设置未开启，不发送微信提醒");
                return;
            }
            // 接收通知的用户
            List<String> userIdList = NoticeKit.getNoticeUserId(empInfoDO.getId(), ruleSettingVO, tokenUser);

            if (CollectionUtils.isEmpty(userIdList)) {
                log.info(noticeCode + "通知设置通知类型：{}，userid为空，不发送微信提醒", ruleSettingVO.getNoticeTypeCode());
            }

            for (String userId : userIdList) {
                if (ruleSettingVO.getReceiveType().contains("weiXin")) {
                    // 校验员工设置
                    UnionOpenIdDO unionOpenIdDO = userProviderService.getUnionOpenByUserId(appId, userId);
                    if (Objects.nonNull(unionOpenIdDO) && StringUtils.isNotEmpty(unionOpenIdDO.getOpenId())) {
                        String openId = unionOpenIdDO.getOpenId();
                        // 推送微信模板消息
                        WeiXinDTO weiXinDTO = new WeiXinDTO();
                        weiXinDTO.setAppId(appId);
                        weiXinDTO.setTemplateId(templateId);
                        weiXinDTO.setToUser(openId);
                        // 参数
                        List<WxTemplateParam> paramList = new ArrayList<>();
                        WxTemplateParam param1 = new WxTemplateParam();
                        param1.setName("first");
                        param1.setValue("您好，员工的电子合同已签订成功。「" + companyName + "」");
                        paramList.add(param1);
                        // 合同签署编号
                        WxTemplateParam param2 = new WxTemplateParam();
                        param2.setName("keyword1");
                        param2.setValue(contractDO.getSignNo());
                        paramList.add(param2);
                        // 甲方名称
                        WxTemplateParam param3 = new WxTemplateParam();
                        param3.setName("keyword2");
                        param3.setValue(contractDO.getPartyAName());
                        paramList.add(param3);
                        // 乙方名称
                        WxTemplateParam param4 = new WxTemplateParam();
                        param4.setName("keyword3");
                        param4.setValue(contractDO.getPartyBName());
                        paramList.add(param4);
                        // 签署时间
                        WxTemplateParam param5 = new WxTemplateParam();
                        param5.setName("keyword4");
                        param5.setValue(DateKit8.getCurrentDay(DateKit8.DATE));
                        paramList.add(param5);

                        WxTemplateParam param7 = new WxTemplateParam();
                        param7.setName("remark");
                        param7.setValue("请仔细查看电子合同文件");
                        paramList.add(param7);

                        weiXinDTO.setTemplateParamList(paramList);

                        // 跳转小程序
                    /*String miNiAppId = siteConfigProviderService.selectValueByCode(ConfigCodeConstants.CODE_MINI_APPID, tokenUser.getSiteId());
                    String miNiPagePath = siteConfigProviderService.selectValueByCode(ConfigCodeConstants.CODE_MINI_PAGE_PATH, tokenUser.getSiteId());
                    WxMiNiParam wxMiNiParam = new WxMiNiParam();
                    wxMiNiParam.setAppid(miNiAppId);
                    wxMiNiParam.setPagepath(miNiPagePath);
                    weiXinDTO.setMiniProgram(wxMiNiParam);*/

                        messageProviderService.sendWeChatTempMessage(weiXinDTO, tokenUser);
                    } else {
                        log.error("未查询到用户unionOpenIdDO信息，userId:{}", userId);
                    }
                }
                if (ruleSettingVO.getReceiveType().contains("system")) {
                    // 电脑端通知
                    noticeProviderService.empSignOverNoticeSend(companyId, userId, contractDO.getPartyBName()
                            + " 合同员工签署成功，请及时处理", contractDO.getPartyAName(), tokenUser);
                }

            }
        } catch (Exception e) {
            log.error("员工签署合同发送通知失败，原因：{}" + e.getMessage());
        }
    }

}
